#include <ESP8266WiFi.h>
#include <ThingSpeak.h>

WiFiClient client;

const char* ssid = "WIFI USERNAME";
const char* password = "WIFI PASSWORD";

unsigned long channelID = THINGSPEAK CHANNEL ID;
const char* writeAPIKey = "THINGSPEAK API KEY";

bool receiving = false;
String value = "";

int packetDigits = 0;

void flash(int count, int onTime = 120, int offTime = 120)
{
  for (int i = 0; i < count; i++)
  {
    digitalWrite(LED_BUILTIN, LOW);
    delay(onTime);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(offTime);
  }
}

void flashShort()
{
  digitalWrite(LED_BUILTIN, LOW);
  delay(20);
  digitalWrite(LED_BUILTIN, HIGH);
}

void flashLong()
{
  digitalWrite(LED_BUILTIN, LOW);
  delay(400);
  digitalWrite(LED_BUILTIN, HIGH);
}

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);

  Serial.begin(9600);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
  }

  ThingSpeak.begin(client);
}

void resetPacket()
{
  receiving = false;
  value = "";
  packetDigits = 0;
}

void loop()
{
  while (Serial.available())
  {
    char c = Serial.read();

    flashShort();

    // START
    if (c == 'T')
    {
      receiving = true;
      value = "";
      packetDigits = 0;
    }

    // END
    else if (c == 'E')
    {
      if (receiving)
      {
        receiving = false;

        // VALIDATION RULES
        if (packetDigits >= 1 && packetDigits <= 3)
        {
          int response = ThingSpeak.writeField(
            channelID,
            1,
            value,
            writeAPIKey
          );

          if (response == 200)
          {
            flashLong(); // SUCCESS
          }
          else
          {
            flash(5); // upload failed
          }
        }
        else
        {
          flash(3); // INVALID PACKET (missing or corrupted)
        }

        resetPacket();
      }
    }

    // DATA
    else if (receiving)
    {
      if (isDigit(c))
      {
        value += c;
        packetDigits++;
      }
      else
      {
        // noise inside packet → invalidate immediately
        resetPacket();
      }
    }
  }
}